#include "ThirdModule.h"


ThirdModule::ThirdModule(NxScene* scene, NxVec3 position): m_object(scene), m_position(position), m_scene(scene)
{
}

ThirdModule::~ThirdModule(void)
{
}

NxActor* ThirdModule::CreateThirdModule(void)
{
	//create the spaceship
	NxVec3 spaceshipPosition = NxVec3(3.5, 5, 0) + m_position;
	NxActor* spaceship = createSpaceShip(spaceshipPosition, NxVec3(0, 0, 0));
	spaceship->setSleepLinearVelocity(2);

	//create the joint between the string a a kinematic object
	NxRevoluteJointDesc joint;
	joint.actor[1] = 0;
	joint.actor[0] = spaceship;

	NxVec3 anchor = spaceshipPosition + NxVec3(-10, 3, 0);

	joint.setGlobalAnchor(anchor);
	joint.setGlobalAxis(NxVec3(0, 0, 1));

	joint.jointFlags =NX_JF_COLLISION_ENABLED;

	joint.projectionMode = NX_JPM_POINT_MINDIST;
	joint.projectionDistance = 0;
	joint.projectionAngle = (float)0.0872;

	NxJoint* newJoint = m_scene->createJoint(joint);

	//create the base for the spaceship
	NxVec3 baseSize(2, 0.5, 2);
	NxVec3 basePosition = spaceshipPosition + NxVec3(0, 0, 0);
	NxVec3 baseRotation(0, 0, 0);
	NxVec3 baseFriction(0, 0, 0);
	m_object.CreateKinematicBox(baseSize, basePosition, baseRotation, baseFriction);

	//create the seesaw
	NxVec3 seesawPosition = NxVec3(-19, 4, 0) + m_position;
	createSeesaw(seesawPosition);

	//create the rock on the seesaw
	NxVec3 rockSize((float)0.7, (float)0.7, (float)0.7);
	NxVec3 rockPosition = NxVec3(-22, 5, 0) + m_position;
	NxVec3 rockFriction(1, 1, 0);
	m_object.CreateBox(rockSize, rockPosition, rockFriction, 7);

	//create the slope
	createTruckSlope(NxVec3(11.5, 10, 0)+m_position);

	//put the truck at start of the slope
	m_object.CreateBox(NxVec3(0.5, 0.5, 0.5), NxVec3(11.5, 12, -1) + m_position, NxVec3(0, 0, 1), 30);

	//create the marbles
	NxVec3 marblePosition = NxVec3((float)26.5, (float)7.6, (float)-0.8) + m_position;
	createMarbles(marblePosition);

	//return the spaceship
	return spaceship;

}

NxActor* ThirdModule::createSpaceShip(const NxVec3& position, const NxVec3& rotation)
{
	float spaceshipHeight = 1.5;
	//actor description
	NxActorDesc actorDesc;

	//create the body of spaceship
	NxBoxShapeDesc bodySpaceship;
	bodySpaceship.dimensions.set(0.5, spaceshipHeight, 0.5);
	bodySpaceship.localPose.t = NxVec3(0, 4, 0);
	bodySpaceship.mass = 100;
	bodySpaceship.skinWidth = 0;
	actorDesc.shapes.push_back(&bodySpaceship);

	//create the bottom
	NxBoxShapeDesc bottomSpaceshp;
	bottomSpaceshp.dimensions.set(0.75, 0.5, 0.75);
	bottomSpaceshp.localPose.t = NxVec3(0, 2, 0);
	bottomSpaceshp.skinWidth = 0;
	actorDesc.shapes.push_back(&bottomSpaceshp);

	//create the engines
	const int numberOfEngines = 4;

	NxBoxShapeDesc enginesSpaceship[numberOfEngines];
	for(int i=0; i<numberOfEngines; i++)
	{
		enginesSpaceship[i].dimensions.set((float)0.3, (float)0.5, (float)0.3);
		enginesSpaceship[i].localPose.t = NxVec3((float)(cos(2*3.14/numberOfEngines*i)*0.75), 1, (float)(sin(2*3.14/numberOfEngines*i)*0.75));
		actorDesc.shapes.push_back(&enginesSpaceship[i]);
	}
	
	//create the top
	NxSphereShapeDesc topSpaceship;
	topSpaceship.radius = 0.5;
	topSpaceship.localPose.t = NxVec3(0, 5.5, 0);
	topSpaceship.skinWidth = 0;
	actorDesc.shapes.push_back(&topSpaceship);

	//create the string
	NxVec3 stringSize(5, (float)0.2, (float)0.2);
	NxVec3 stringPosition(-5, 5, 0);
	NxVec3 friction(0, 0, 0);

	NxBoxShapeDesc boxDesc;
	boxDesc.mass = (float)0.1;
	boxDesc.dimensions.set(stringSize.x, stringSize.y, stringSize.z);
	boxDesc.localPose.t = stringPosition;

	//create the material of the box
	NxMaterialDesc material;
	material.dynamicFriction = friction.x;
	material.staticFriction = friction.y;
	material.restitution = friction.z;
	int materialIndex = m_scene->createMaterial(material)->getMaterialIndex();

	boxDesc.materialIndex = materialIndex;
	actorDesc.shapes.push_back(&boxDesc);

	actorDesc.density		= 10.0f;
	actorDesc.globalPose.t	= position;

	NxBodyDesc bodyDesc;
	actorDesc.body = &bodyDesc;

	
	
	return m_scene->createActor(actorDesc);
}

void ThirdModule::createSeesaw(const NxVec3& position)
{
	NxBoxShapeDesc balanceDesc;
	NxActorDesc actorDesc;

	//balance
	balanceDesc.dimensions.set(5, (float)0.2, 2);
	balanceDesc.localPose.M.rotZ((float)3.14/8);
	balanceDesc.skinWidth = 0;

	//create the material of the box
	NxMaterialDesc material;
	material.dynamicFriction = 1;
	material.staticFriction = 1;
	material.restitution = 0;
	int materialIndex = m_scene->createMaterial(material)->getMaterialIndex();

	balanceDesc.materialIndex = materialIndex;

	actorDesc.shapes.push_back(&balanceDesc);
	NxBodyDesc body;
	actorDesc.body = &body;
	actorDesc.density = 10.0f;
	actorDesc.globalPose.t = position;

	NxActor* seesaw = m_scene->createActor(actorDesc);

	//create the joint
	NxRevoluteJointDesc joint;
	joint.actor[1] = 0;
	joint.actor[0] = seesaw;

	NxVec3 anchor = position;

	joint.setGlobalAnchor(anchor);
	joint.setGlobalAxis(NxVec3(0, 0, 1));

	joint.jointFlags =NX_JF_COLLISION_ENABLED;

	joint.projectionMode = NX_JPM_POINT_MINDIST;
	joint.projectionDistance = 0;
	joint.projectionAngle = (float)0.0872;

	NxJoint* newJoint = m_scene->createJoint(joint);

	//create a ground under it
	NxVec3 groundSize(7, (float)0.2, 3);
	NxVec3 groundPosition = position + NxVec3(-3, -2, 0);
	NxVec3 groundRotation(0, 0, 0);
	NxVec3 groundFriction(1, 1, 0);
	m_object.CreateKinematicBox(groundSize, groundPosition, groundRotation, groundFriction);
}
void ThirdModule::createTruckSlope(const NxVec3& position)
{
	//create the slope for the truck
	NxVec3 positionStart = position;
	NxVec3 sizeStart(1, 0.5, 2);
	NxVec3 rotationStart(0, 0, 0);
	NxVec3 frictionStart((float)0.15, 0, 0);
	m_object.CreateKinematicBox(sizeStart, positionStart, rotationStart, frictionStart);

	//create the slope
	const int numberOfPart = 15;
	NxBoxShapeDesc arraySlope[numberOfPart];
	NxVec3 center= position + NxVec3((float)7.8, -2, 0);

	for(int i=0; i<numberOfPart; i++)
	{
		float totalAngle = (float)(3.14/3*2.7);
		float radius = 7;
		float angle = -totalAngle/numberOfPart*i;
		//angle = 3.14/2+angle;

		NxVec3 size(2, (float)0.2, 2);
		NxVec3 position = center + NxVec3(-cos(angle)*radius, sin(angle)*radius, 0);
		NxVec3 rotation(0, 0, (float)(-(3.14/2+angle)));
		NxVec3 friction(0, 0, 0);
		m_object.CreateKinematicBox(size, position, rotation, friction);
	}

	//create the end of the slope
	NxVec3 endSize(5, 0.5, 2);
	NxVec3 endPosition = center + NxVec3((float)11.9, -2, 0);
	NxVec3 endFriction(0, 0, 0);
	NxVec3 endRotation(0, 0, 0);
	m_object.CreateKinematicBox(endSize, endPosition, endRotation, endFriction);
	
}
void ThirdModule::createTruck(const NxVec3& position)
{
	//actor description
	NxActorDesc actorDesc;

	//creat the body
	NxVec3 bodySize(1, (float)0.3, (float)0.5);
	NxBoxShapeDesc truckBodyDesc;
	truckBodyDesc.dimensions.set(bodySize);
	truckBodyDesc.mass = 20;

	//create the material of the box
	NxMaterialDesc material;
	material.dynamicFriction = 1;
	material.staticFriction = 1;
	material.restitution = 0;
	int materialIndex = m_scene->createMaterial(material)->getMaterialIndex();
	truckBodyDesc.materialIndex = materialIndex;
	actorDesc.shapes.pushBack(&truckBodyDesc);

	//create the front
	NxVec3 frontSize((float)0.3, 0.5, 0.5);
	NxVec3 frontPosition = NxVec3((float)0.7, (float)0.5, 0);
	NxBoxShapeDesc frontDesc;
	frontDesc.dimensions.set(frontSize);
	frontDesc.localPose.t = frontPosition;
	frontDesc.materialIndex = materialIndex;
	actorDesc.shapes.push_back(&frontDesc);

	//create the under part of the truck
	NxMaterialDesc materialUnder;
	materialUnder.dynamicFriction = 0;
	materialUnder.staticFriction = 0;
	materialUnder.restitution = 0;
	int materialIndexUnder = m_scene->createMaterial(materialUnder)->getMaterialIndex();

	NxVec3 underSize(1, (float)0.1, 0.5);
	NxBoxShapeDesc UnderDesc;
	UnderDesc.dimensions.set(underSize);
	UnderDesc.materialIndex = materialIndexUnder;
	UnderDesc.localPose.t = NxVec3(0, (float)-0.3, 0);
	actorDesc.shapes.push_back(&UnderDesc);
	

	NxBodyDesc bodyDesc;
	actorDesc.body			= &bodyDesc;
	actorDesc.density		= 10.0f;
	actorDesc.globalPose.t	= position;	

	//create the actor
	assert(actorDesc.isValid());
	NxActor *pActor = m_scene->createActor(actorDesc);	
	assert(pActor);

}

void ThirdModule::createMarbles(const NxVec3& position)
{
	//create the material of the box
	NxMaterialDesc material;
	material.dynamicFriction = 1;
	material.staticFriction = 1;
	material.restitution = 1;
	int materialIndex = m_scene->createMaterial(material)->getMaterialIndex();

	const int numberOfMarbles = 6;

	NxActorDesc actor[numberOfMarbles];
	NxSphereShapeDesc marbleDesc[numberOfMarbles];
	NxBoxShapeDesc string[numberOfMarbles];
	NxRevoluteJointDesc jointDesc[numberOfMarbles];

	float marbleRadius = 1;

	for(int i=0; i<6; i++)
	{
		//create the marbe
		marbleDesc[i].radius = marbleRadius;
		marbleDesc[i].materialIndex = materialIndex;
		marbleDesc[i].mass = 1;
		actor[i].shapes.push_back(&marbleDesc[i]);

		//create the string
		string[i].dimensions.set((float)0.1, 2, (float)0.1);
		string[i].localPose.t = NxVec3(0, (float)1.2, 0);
		actor[i].shapes.push_back(&string[i]);


		//create the actor
		NxBodyDesc bodyDesc;
		actor[i].body			= &bodyDesc;
		actor[i].density		= 10.0f;
		actor[i].globalPose.t	= position+NxVec3(i*2*marbleRadius, 0, 0);	

		NxActor* actorPtr = m_scene->createActor(actor[i]);	

		//create the joint
		jointDesc[i].actor[1] = 0;
		jointDesc[i].actor[0] = actorPtr;

		NxVec3 anchor = position+NxVec3(i*2*marbleRadius, 2, 0);

		jointDesc[i].setGlobalAnchor(anchor);
		jointDesc[i].setGlobalAxis(NxVec3(0, 0, 1));

		jointDesc[i].jointFlags =NX_JF_COLLISION_ENABLED;

		jointDesc[i].projectionMode = NX_JPM_POINT_MINDIST;
		jointDesc[i].projectionDistance = 0;
		jointDesc[i].projectionAngle = (float)0.0872;

		m_scene->createJoint(jointDesc[i]);

	}
}